package org.dicr.sys.linux;

import java.io.*;
import java.lang.ref.*;
import java.util.logging.*;

/**
 * Датчик памяти.
 * <P>
 * Информация о памяти берется из файла {@link #MEMINFO} и кэшируется в течении {@link #getCacheTime()} периода.
 * </P>
 * 
 * @author Igor A Tarasov, &lt;java@dicr.org&gt;
 * @version 1.0
 * @see MemoryInfoData
 */
public class MemoryInfo {
	/**
     * Файл информации о памяти.
     */
	public static final String MEMINFO = "/proc/meminfo";

	/**
     * Логгер.
     */
	protected static final Logger log = Logger.getLogger(MemoryInfo.class.getName());

	/**
     * Время кэширования данных.
     */
	private static long cacheTime = 1000;

	/**
     * Информация о памяти.
     */
	private static SoftReference<MemoryInfoData> dataRef = null;

	/**
     * Возвращает время кэширования.
     * 
     * @return время кэширования данных в миллисекундах.
     */
	public static synchronized long getCacheTime() {
		return cacheTime;
	}

	/**
     * Устанавливает время кэширования.
     * 
     * @param millisec время кэширования в миллисекундах
     */
	public static synchronized void setCacheTime(long millisec) {
		if (millisec < 0) {
			throw new IllegalArgumentException("cache period must be positive value");
		}
		cacheTime = millisec;
	}

	/**
     * Возвращает информацию о памяти.
     * <P>
     * Данные кэшируются на время <CODE>cacheTimeout</CODE>.
     * 
     * @return информация о памяти
     * @throws IOException ошибка ввода-вывода
     * @throws FileNotFoundException не найден файл состояния памяти {@value #MEMINFO}
     * @throws NumberFormatException ошибка разбора файла.
     * @see #getCacheTime()
     */
	public static synchronized MemoryInfoData getInfo() throws IOException, FileNotFoundException, NumberFormatException {
		MemoryInfoData data = null;
		if (dataRef != null) {
			data = dataRef.get();
		}
		if (data != null && System.currentTimeMillis() - data.getTimeStamp() < cacheTime) {
			return data;
		}
		// refresh data
		BufferedReader in = null;
		try {
			long memTotal = 0;
			long memFree = 0;
			long swapTotal = 0;
			long swapFree = 0;
			in = new BufferedReader(new FileReader(MEMINFO));
			while (true) {
				String s = in.readLine();
				if (s == null) {
					break;
				}
				String tokens[] = s.split("[\\s:]+");
				if (tokens.length < 2) {
					continue;
				}
				String key = tokens[0].toLowerCase();
				long val = Long.parseLong(tokens[1]) * 1024;
				if (key.equals("memtotal")) {
					memTotal = val;
				} else if (key.equals("memfree")) {
					memFree = val;
				} else if (key.equals("swaptotal")) {
					swapTotal = val;
				} else if (key.equals("swapfree")) {
					swapFree = val;
				}
			}
			in.close();
			in = null;
			data = new MemoryInfoData(memTotal, memFree, swapTotal, swapFree);
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (Exception ex) {
					// NOP
				}
			}
		}
		return data;
	}
}
